package com.guisu.material.recyclerview

import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View

/**
- 下拉刷新的RecyclerView
- on 2022/11/7
 */
open class RefreshRecyclerView : WrapRecyclerView {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    )

    /**
     * 下拉刷新的辅助类
     */
    private var refreshCreator: RefreshViewCreator? = null

    /**
     * 下拉刷新头部的高度
     */
    private var refreshViewHeight = 0

    /**
     * 下拉刷新的头部View
     */
    private var refreshView: View? = null

    /**
     * 手指按下Y的位置
     */
    private var fingerDownY = 0

    /**
     * 手指拖拽的阻力指数
     */
    open var dragIndex = 0.35f

    /**
     * 当前是否正在拖动
     */
    private var currentDrag = false

    /**
     * 当前状态
     */
    private var currentRefreshStatus = 0

    /**
     * 默认状态
     */
    private val REFRESH_STATUS_NORMAL = 1

    /**
     * 下拉刷新状态
     */
    private val REFRESH_STATUS_PULL_DOWN_REFRESHING = 2

    /**
     * 松开刷新状态
     */
    private val REFRESH_STATUS_LOOSEN_REFRESHING = 3

    /**
     * 正在刷新状态
     */
    private val REFRESH_STATUS_REFRESHING = 4


    fun addRefreshViewCreator(refreshViewCreator: RefreshViewCreator) {
        this.refreshCreator = refreshViewCreator
        addRefreshView()
    }

    override fun setAdapter(adapter: Adapter<*>?) {
        super.setAdapter(adapter)
        addRefreshView()
    }


    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                //记录手指按下的位置
                fingerDownY = ev.rawY.toInt()
            }

            MotionEvent.ACTION_UP -> {
                if (currentDrag) {
                    restoreRefreshView()
                }
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    /**
     * 重置当前刷新状态
     */
    private fun restoreRefreshView() {
        val currentTopMargin = (refreshView?.layoutParams as MarginLayoutParams).topMargin // 假如10dp
        var finalTopMargin = -refreshViewHeight + 1 // 加入-100 + 1 = -99
        if (currentRefreshStatus == REFRESH_STATUS_LOOSEN_REFRESHING) {
            finalTopMargin = 0
            currentRefreshStatus = REFRESH_STATUS_REFRESHING
            refreshCreator?.onRefreshing()
            listener?.onRefresh()
        }

        val distance = currentTopMargin - finalTopMargin // 10 + 99 = 109db

        //回弹到指定位置

        val animator: ValueAnimator =
            ObjectAnimator.ofFloat(currentTopMargin.toFloat(), finalTopMargin.toFloat())
                .setDuration(distance.toLong())
        animator.addUpdateListener {
            val currentTopMargin = it.animatedValue as Float
            setRefreshViewMarginTop(currentTopMargin.toInt())
        }

        animator.start()
        currentDrag = false

    }


    override fun onTouchEvent(ev: MotionEvent): Boolean {
        when (ev.action) {
            MotionEvent.ACTION_MOVE -> {
                //在最顶部的时候才处理，否则不需要处理
                if (canScrollUp() || currentRefreshStatus == REFRESH_STATUS_REFRESHING || refreshView == null || refreshCreator == null) {
                    //如果没有到达最顶端，也就是说还可以向上滚动就什么都不处理
                    return super.onTouchEvent(ev)
                }
                //解决下拉刷新自动滚动问题
                if (currentDrag) {
                    scrollToPosition(0)
                }
                //获取手指触摸拖拽的距离
                val distanceY = (ev.rawY - fingerDownY) * dragIndex
                //如果是已经到达头部，并且不断的向上拉，那么不断的改变refreshView的marginTop的值
                if (distanceY > 0) {
                    val marginTop = distanceY - refreshViewHeight
                    setRefreshViewMarginTop(marginTop.toInt())
                    updateRefreshStatus(distanceY)
                    currentDrag = true
                    return false
                }
            }
        }
        return super.onTouchEvent(ev)
    }


    /**
     * 更新刷新状态
     */
    private fun updateRefreshStatus(distanceY: Float) {
        currentRefreshStatus = if (distanceY <= 0) {
            REFRESH_STATUS_NORMAL
        } else if (distanceY < refreshViewHeight) {
            REFRESH_STATUS_PULL_DOWN_REFRESHING
        } else {
            REFRESH_STATUS_LOOSEN_REFRESHING
        }
        refreshCreator?.onPull(distanceY.toInt(), refreshViewHeight, currentRefreshStatus)

    }


    /**
     * 添加头部刷新View
     */
    private fun addRefreshView() {
        if (adapter != null && refreshCreator != null) {
            val refreshView = refreshCreator?.getRefreshView(context, this)
            if (refreshView != null) {
                addHeaderView(refreshView)
                this.refreshView = refreshView
            }
        }
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        if (refreshView != null && refreshViewHeight <= 0) {
            //获取头部刷新View的高度
            refreshViewHeight = refreshView?.measuredHeight!!
            if (refreshViewHeight > 0) {
                //隐藏头部刷新的View  marginTop 多留出1px防止无法判断是不是滑动到头部问题
                setRefreshViewMarginTop(-refreshViewHeight + 1)
            }
        }
    }

    private fun setRefreshViewMarginTop(marginTop: Int) {
        var finalMarginTop = marginTop
        val params = refreshView?.layoutParams as MarginLayoutParams
        if (finalMarginTop < -refreshViewHeight + 1) {
            finalMarginTop = -refreshViewHeight + 1
        }
        params.topMargin = finalMarginTop
        refreshView?.layoutParams = params
    }


    private fun canScrollUp(): Boolean {
        return canScrollVertically(-1) || scrollY > 0
    }


    fun onStopRefresh() {
        currentRefreshStatus = REFRESH_STATUS_NORMAL
        restoreRefreshView()
        refreshCreator?.onStopRefresh()
    }


    private var listener: OnRefreshListener? = null

    fun setOnRefreshListener(listener: OnRefreshListener) {
        this.listener = listener
    }

    interface OnRefreshListener {
        fun onRefresh()
    }
}
